%name grammar_pattern_

%include {
    global $CFG;
    require_once($CFG->dirroot . '/blocks/formal_langs/tokens_base.php');
    require_once($CFG->dirroot . '/blocks/formal_langs/grammar_pattern.php');
}

%include_class {
    public $error;
    public $list = array();
    public $start;
    public $success = false;

    private $debug_mode = false;

    public function dump() {
        if ($this->debug_mode) {
            ob_start();
            $this->dump_info .= "<pre>Stack dump:\n";
            var_dump($this->yystack);
            $this->dump_info .= ob_get_contents();
            ob_end_clean();

            ob_start();
            $this->dump_info .= "$this->list dump:\n";
            var_dump($this->ast);
            $this->dump_info .= ob_get_contents();
            ob_end_clean();

            ob_start();
            $this->dump_info .= "$this->error dump:\n";
            var_dump($this->error);
            $this->dump_info .= ob_get_contents();
            ob_end_clean();
            $this->dump_indo .= "</pre>";
        }
    }

    public function process_token($token) {
        $this->doParse($token->type(), $token);
    }
 }

%parse_failure {
    if ($this->debug_mode) {
        $this->dump_info .= "Parsing error.\n";
        $this->dump();
    }
    $this->success = false;
 }

%parse_accept {
    if ($this->debug_mode) {
        $this->dump_info .= "Parsing done.\n";
        $this->dump();
    }
    $this->success = true;
 }

%syntax_error {
    if ($this->debug_mode) {
        $this->dump_info .= "Syntax error.\n";
    }
 }

start ::= patterns(B) . {
    $this->list = B;
}

patterns(A) ::= pattern(B) . {
    A = array();
    A[] = B;
}
patterns ::= startrule(B) . {
    $this->start = B;
}
patterns(A) ::= patterns(B) pattern(C) . {
    B[] = C;
    A = B;
}
patterns(A) ::= patterns(B) startrule(C) . {
    $this->start = C;
    A = B;
}

startrule(A) ::= START NONTERMINAL(B) SEMICOLON . {
    A = B;
}
     
pattern(A) ::= NONTERMINAL(B) options(C) STRING(D) COLON right_part(E) SEMICOLON . {
    $res = new block_formal_langs_parser_rule(B, E, D, C);
    A = $res;
}
pattern(A) ::= NONTERMINAL(B)            STRING(D) COLON right_part(E) SEMICOLON . {
    $res = new block_formal_langs_parser_rule(B, E, D);
    A = $res;
}
pattern(A) ::= NONTERMINAL(B)                      COLON right_part(E) SEMICOLON . {
    $res = new block_formal_langs_parser_rule(B, E);
    A = $res;
}

options(A) ::= option(B) .{
    A = array();
    A[] = B;
}
options(A) ::= options(B) COMMA option(C) . {
    B[] = C;
    A = B;
}

option(A) ::= option_name(B) LPAREN option_args(C) RPAREN . {
    $res = new block_formal_langs_parser_option(B, C);
    A = $res;
}
option(A) ::= option_name(B) . {
    $res = new block_formal_langs_parser_option(B);
    A = $res;
}

option_name(A) ::= OPTION_LIST(B) . {
    A = B;
}

option_args(A) ::= option_arg(B) . {
    A = array();
    A[] = B;
}
option_args(A) ::= option_args(B) COMMA option_arg(C) . {
    B[] = C;
    A = B;
}

option_arg(A) ::= ID(B) . {
    A = B;
}
option_arg(A) ::= TERMINAL(B) . {
    A = B;
}
option_arg(A) ::= NONTERMINAL(B) . {
    A = B;
}
option_arg(A) ::= NUMBER(B) . {
    A = intval(B);
}

right_part(A) ::= alternatives(B) . {
    A = B;
}

alternatives(A) ::= alternative(B) . {
    A = array();
    A[] = B;
}
alternatives(A) ::= alternatives(B) BAR alternative(C) . {
    B[] = C;
    A = B;
}

alternative(A) ::= elements_e(B) STRING(C) translations_e(D). {
    $res = new block_formal_langs_parser_rule_alternative(B, C, D);
    A = $res;
}
alternative(A) ::= elements_e(B)           translations_e(D) . {
    $res = new block_formal_langs_parser_rule_alternative(B, null, D);
    A = $res;
}

elements_e(A) ::= elements(B) . {
    A = B;
}
elements_e(A) ::= . {
    A = array();
    A[] = "%empty";
}
    
elements(A) ::= element(B) . {
    A = array();
    A[] = B;
}
elements(A) ::= elements(B) element(C) . {
    B[] = C;
    A = B;
}

element(A) ::= ID(B) . {
    A = B;
}
element(A) ::= TERMINAL(B) . {
    A = B;
}
element(A) ::= NONTERMINAL(B) . {
    A = B;
}

translations_e(A) ::= COLON translations(B) . {
    A = B;
}
translations_e(A) ::= . {
    A = NULL;
}
    
translations(A) ::= STRING(B) . {
    A = array();
    A[] = B;
}
translations(A) ::= translations(B) STRING(C) . {
    B[] = C;
    A = B;
}
